home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BasicLargeTreeModelNode.java < prev    next >
Text File  |  1998-06-30  |  12KB  |  323 lines

  1. /*
  2.  * @(#)BasicLargeTreeModelNode.java    1.11 98/02/02
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.basic;
  22.  
  23. import com.sun.java.swing.CellRendererPane;
  24. import com.sun.java.swing.JTree;
  25. import com.sun.java.swing.tree.*;
  26. import com.sun.java.swing.*;
  27. import java.awt.Color;
  28. import java.awt.Component;
  29. import java.awt.Graphics;
  30. import java.util.*;
  31. import java.awt.*;
  32.  
  33. /**
  34.  * BasicLargeTreeModelNode extends LargeTreeModelNode to handle painting,
  35.  * as well as stopping editing at crucial points.<p>
  36.  *
  37.  * @version 1.11 02/02/98
  38.  * @author Scott Violet
  39.  */
  40. class BasicLargeTreeModelNode extends LargeTreeModelNode {
  41.     public BasicLargeTreeModelNode(AbstractTreeUI treeUI, Object userObject,
  42.                    int childIndex) {
  43.     super(treeUI, userObject, childIndex);
  44.     }
  45.  
  46.     /**
  47.      * Repaints the receiver by messaging the TreeUI with repaintNode.
  48.      */
  49.     public void repaint() {
  50.     ((BasicTreeUI)treeUI).repaintNode(this);
  51.     }
  52.  
  53.     /**
  54.      * Messages the BasicTreeUI the receiver was crated for to stop
  55.      * editing.
  56.      */
  57.     public void cancelEditing() {
  58.     ((BasicTreeUI)treeUI).completeEditing(false, true, false);
  59.     }
  60.  
  61.     /**
  62.      * If the node is visible, it is repainted.
  63.      */
  64.     public void modelChildCountChanged() {
  65.     if(getRow() != -1)
  66.         repaint();
  67.     }
  68.  
  69.     /**
  70.      * Stops editing, repaints the node if only 1 child and messages
  71.      *  super.
  72.      */
  73.     public void insert(MutableTreeNode newChild, int childIndex) {
  74.     cancelEditing();
  75.     super.insert(newChild, childIndex);
  76.     if(getChildCount() == 1 && getRow() != -1)
  77.         repaint();
  78.     }
  79.  
  80.     /**
  81.      * Stops editing, repaints if no children, and messages super.
  82.      */
  83.     public void remove(int childIndex) {
  84.     cancelEditing();
  85.     super.remove(childIndex);
  86.     if(treeUI.getModel().getChildCount(getUserObject()) == 0 &&
  87.        getRow() != -1)
  88.         repaint();
  89.     }
  90.  
  91.     /**
  92.      * Stops editing messages super and repaints this node if
  93.      * there are no children.
  94.      */
  95.     public void collapse(boolean adjustTree) {
  96.     cancelEditing();
  97.     super.collapse(adjustTree);
  98.     if(adjustTree && (children == null || children.size() == 0))
  99.         repaint();
  100.     }
  101.  
  102.     /**
  103.      * Stops editing messages super and repaints this node if
  104.      * there are no children.
  105.      */
  106.     public void expand(boolean adjustTree) {
  107.     cancelEditing();
  108.     super.expand(adjustTree);
  109.     if(adjustTree && (children == null || children.size() == 0))
  110.         repaint();
  111.     }
  112.  
  113.     /**
  114.      * Paints the node identified by value at the specified row.<p>
  115.      * NOTE: The receiver may not actual represent value. A
  116.      * LargeTreeModelNode is not created for each value, and as such someone
  117.      * needs to draw the values that aren't represented. Generally the
  118.      * value will either be receiver or one of its children.<p>
  119.      * NOTE: <code>child</code> may be null, which implies that child
  120.      * has not been loaded yet (or is a leaf).<p>
  121.      * NOTE: It may be faster to have the parents draw the vertical hashes
  122.      * here while descending! The only disadvantage is that it would
  123.      * require counting all the children of a given parent to determine
  124.      * the ending row. It could probably be sped up though, so this
  125.      * should be investigated.
  126.      */
  127.     protected void paintNode(Hashtable graphicsCache, BasicTreeUI.BasicTreeUIPaintInfo pInfo, int row,
  128.                  int depth,
  129.                  Object value, boolean isLeaf,
  130.                  boolean isExpanded, LargeTreeModelNode parent,
  131.                  int childIndex, LargeTreeModelNode childNode) {
  132.     int       x = (pInfo.levelOffset + depth) * pInfo.totalIndent;
  133.     int       y = pInfo.rowHeight * row;
  134.     int       rChildIndent = pInfo.rChildIndent;
  135.     int       minX = x - (rChildIndent - 1);
  136.     int       midY = y + pInfo.halfRowHeight;
  137.     int       maxY = y + (pInfo.rowHeight - 1);
  138.     Color     hColor = pInfo.hashColor;
  139.     Graphics  g = pInfo.g;
  140.     BasicTreeUI    ui = (BasicTreeUI)treeUI;
  141.     TreeModel      treeModel = pInfo.treeModel;
  142.     Component      rComponent;
  143.  
  144.     rComponent = pInfo.renderer.getTreeCellRendererComponent
  145.         (pInfo.tree, value,ui.isRowSelected(row), isExpanded, isLeaf, row,
  146.          (row == pInfo.leadIndex));
  147.     if(hColor != null) {
  148.         int             lastChildIndex = childIndex;
  149.         LargeTreeModelNode    lastParent = parent;
  150.  
  151.         g.setColor(hColor);
  152.         /* Draw the horizontal line. */
  153.         if(row != 0 || pInfo.levelOffset == 1)
  154.             ui.drawHorizontalPartOfLeg( g, pInfo.tree, midY, minX, x );
  155.     }
  156.     /* Only draw icons if has children. */
  157.     if (!isLeaf && (childNode == null ||
  158.             treeModel.getChildCount(value) > 0)) {
  159.         if (isExpanded) {
  160.         if(pInfo.expandedIcon != null)
  161.             cacheIconPainting( graphicsCache, pInfo.expandedIcon, minX, midY );
  162.         //ui.drawCentered(pInfo.tree, g, pInfo.expandedIcon, minX, midY);
  163.         } else {
  164.         if(pInfo.collapsedIcon != null)
  165.             cacheIconPainting( graphicsCache, pInfo.collapsedIcon, minX, midY );
  166.         //ui.drawCentered(pInfo.tree, g, pInfo.collapsedIcon, minX, midY);
  167.         }
  168.     }
  169.  
  170.     ui.rendererPane.paintComponent(g, rComponent, pInfo.tree, x, y, 
  171.                     rComponent.getPreferredSize().width,
  172.                     pInfo.rowHeight, true);
  173.     }
  174.  
  175.     protected void cacheIconPainting( Hashtable graphicsCache, Icon icon, int minX, int midY ) {
  176.         graphicsCache.put( new Point( minX, midY ), icon );
  177.     }
  178.  
  179.     public static void paintCachedGraphics( Hashtable graphicsCache, Graphics g, JTree tree, BasicTreeUI ui ) {
  180.         Enumeration keys = graphicsCache.keys();
  181.  
  182.     while ( keys.hasMoreElements() ) {
  183.         Point point = (Point)keys.nextElement();
  184.         Icon icon = (Icon)graphicsCache.get( point );
  185.         ui.drawCentered( tree, g, icon, point.x, point.y );
  186.     }
  187.     }
  188.  
  189.     /**
  190.      * Paints all the children that do not have LargeTreeModelNodes by
  191.      * messaging paintNode.<p>
  192.      * <code>beginRow</code> specifies the beginining row to paint
  193.      * at and <code>endRow</code> specifies the row to stop painting
  194.      * at. <code>lowerTest</code> specifies the potential lower row
  195.      * to start painting at and <code>upperTest</code> specifies the
  196.      * potential upper row to start painting at.
  197.      */
  198.     protected void paintChildren(Hashtable graphicsCache, BasicTreeUI.BasicTreeUIPaintInfo pInfo,
  199.                  int lowerTest,
  200.                  int upperTest, int beginRow, int endRow,
  201.                  int depth, int lowerChildIndex) {
  202.     int       minRow = Math.max(beginRow, lowerTest);
  203.     int       minIndex = (minRow - lowerTest) + lowerChildIndex;
  204.     int       firstIndex = minIndex;
  205.     int       maxIndex = (Math.min(endRow, upperTest) - lowerTest) +
  206.                           lowerChildIndex;
  207.     Object    childValue;
  208.  
  209.     while(minIndex <= maxIndex) {
  210.         childValue = pInfo.treeModel.getChild(getUserObject(), minIndex);
  211.         paintNode(graphicsCache, pInfo, minRow, depth, childValue,
  212.               pInfo.treeModel.isLeaf(childValue), false, this,
  213.               minIndex, null);
  214.         minIndex++;
  215.         minRow++;
  216.     }
  217.     }
  218.  
  219.     /**
  220.      * Paints this node if currentRow[0] is between beginRow and
  221.      * endRow by messaging paintNode. Will then message all the children
  222.      * will paint, and for nodes that are in between beginRow/endRow
  223.      * and don't have an LargeTreeModelNode paintChildren will be messaged.
  224.      */
  225.     protected boolean paint(Hashtable graphicsCache, BasicTreeUI.BasicTreeUIPaintInfo pInfo,
  226.                 int currentRow[], int beginRow, int endRow,
  227.                 int depth) {
  228.     // Current row of the receiver.
  229.     int startRow = currentRow[0];
  230.  
  231.     if(currentRow[0] >= beginRow && currentRow[0] <= endRow)
  232.         paintNode(graphicsCache, pInfo, currentRow[0], depth, getUserObject(),
  233.               false, isExpanded(), (LargeTreeModelNode)getParent(),
  234.               getChildIndex(), this);
  235.     currentRow[0]++;
  236.     if(currentRow[0] > endRow)
  237.         return true;
  238.     depth++;
  239.     if(isExpanded) {
  240.         BasicLargeTreeModelNode  aChild;
  241.         int                      childIndex;
  242.         int                      lastChildIndex = 0;
  243.         int                      lastRow = currentRow[0];
  244.         int                      newRow;
  245.         // Number of children, from the model, minus 1.
  246.         int                      modelChildCount = pInfo.treeModel.
  247.                                   getChildCount(getUserObject()) - 1;
  248.         // Will be set to row of our last child, if it is expanded.
  249.         int                      lastChildRow = -1;
  250.  
  251.         for(int counter = 0, maxCounter = getChildCount();
  252.         counter < maxCounter; counter++) {
  253.         aChild = (BasicLargeTreeModelNode)getChildAt(counter);
  254.         childIndex = aChild.childIndex;
  255.         if(childIndex != lastChildIndex) {
  256.             /* Subtract one to not paint this child, that will be
  257.                done below. */
  258.             newRow = (childIndex - lastChildIndex) + lastRow - 1;
  259.             if(lastRow <= endRow && (newRow >= beginRow ||
  260.                          newRow <= endRow)) {
  261.             paintChildren(graphicsCache, pInfo, lastRow, newRow,
  262.                       beginRow, endRow, depth,
  263.                       lastChildIndex);
  264.             }
  265.         }
  266.         currentRow[0] += (childIndex - lastChildIndex);
  267.         if(currentRow[0] > endRow) {
  268.             // The children of this node go beyond the visible
  269.             // region, paint the legs from the starting row to the
  270.             // end row, don't actually need the real last y as it'll
  271.             // be clipped anyway.
  272.             ((BasicTreeUI)treeUI).drawVerticalPartOfLeg(pInfo.g, pInfo.tree, depth-1,
  273.                             startRow * pInfo.rowHeight,
  274.                             endRow * pInfo.rowHeight, pInfo.rowHeight,
  275.                             pInfo.rowHeight);
  276.             return true;
  277.         }
  278.         // If this child is the last child in the model, record
  279.         // its row.
  280.         if(childIndex == modelChildCount)
  281.             lastChildRow = currentRow[0];
  282.         aChild.paint(graphicsCache, pInfo, currentRow, beginRow, endRow, depth);
  283.         lastRow = currentRow[0];
  284.         lastChildIndex = childIndex + 1;
  285.         }
  286.         childIndex = pInfo.treeModel.getChildCount(getUserObject()) - 1;
  287.         if(childIndex >= lastChildIndex) {
  288.         newRow = (childIndex - lastChildIndex) + lastRow;
  289.         if(lastRow <= endRow && (newRow >= beginRow ||
  290.                      newRow <= endRow)) {
  291.             paintChildren(graphicsCache, pInfo, lastRow, newRow,
  292.                   beginRow, endRow, depth,
  293.                   lastChildIndex);
  294.         }
  295.         currentRow[0] += (childIndex - lastChildIndex) + 1;
  296.         }
  297.         // If we have children, we need to draw the legs from the start
  298.         // row down to either lastChildRow, or currentRow[0]
  299.         // lastChildRow will be valid if our last child is expanded.
  300.         if(modelChildCount >= 0) {
  301.         ((BasicTreeUI)treeUI).drawVerticalPartOfLeg(pInfo.g, pInfo.tree, depth-1,
  302.                                   startRow * pInfo.rowHeight,
  303.                   ((lastChildRow == -1) ? (currentRow[0] - 1) :
  304.                    lastChildRow) * pInfo.rowHeight, pInfo.rowHeight,
  305.                         pInfo.rowHeight);
  306.         }
  307.     }
  308.     return false;
  309.     }
  310.  
  311.     /**
  312.      * This will paint all nodes in the tree "below" this one.  This method is usually
  313.      * called on the "root" node.
  314.      */
  315.     public void paintAll(BasicTreeUI.BasicTreeUIPaintInfo pInfo,
  316.                 int currentRow[], int beginRow, int endRow,
  317.                 int depth, BasicTreeUI ui ) {
  318.         Hashtable graphicsCache = new Hashtable();
  319.     paint( graphicsCache, pInfo, currentRow, beginRow, endRow, depth );
  320.     paintCachedGraphics( graphicsCache, pInfo.g, pInfo.tree, ui );
  321.     }
  322. }
  323.